//
//  YSLoadingView.m
//  YSKitDemo
//
//  Created by MOLBASE on 2018/8/15.
//  Copyright © 2018年 YangShen. All rights reserved.
//

#import "YSLoadingView.h"

#define YSLoadingImage(file)  [UIImage imageNamed:file]

@interface YSLoadingView () <CAAnimationDelegate>

/** 背景layer */
@property (nonatomic, strong) CAShapeLayer *backgroundLayer;

/** 动画layer */
@property (nonatomic, strong) CAShapeLayer *animatedLayer;

/** 加载方式 */
@property (nonatomic, assign) YSLoadingStyle loadingStyle;

/** 失败tiplabel */
@property (nonatomic, strong) UILabel       *failureLabel;

@end

@implementation YSLoadingView

+ (instancetype)loadingViewWithFrame:(CGRect)frame style:(YSLoadingStyle)style {
    return [[self alloc] initWithFrame:frame loadingStyle:style];
}

- (instancetype)initWithFrame:(CGRect)frame loadingStyle:(YSLoadingStyle)loadingStyle {
    if (self = [super initWithFrame:frame]) {
        self.backgroundColor = [UIColor clearColor];
        self.loadingStyle   = loadingStyle;

        // 设置默认值
        self.lineWidth      = 4;
        self.radius         = 24;
        self.bgColor        = [[UIColor blackColor] colorWithAlphaComponent:0.5];
        self.strokeColor    = [UIColor whiteColor];
    }
    return self;
}

- (void)willMoveToSuperview:(UIView *)newSuperview {
    if (newSuperview) {
        [self layoutAnimatedLayer];
    } else {
        [self.animatedLayer removeFromSuperlayer];
        self.animatedLayer = nil;

        [self.backgroundLayer removeFromSuperlayer];
        self.backgroundLayer = nil;
    }
}

- (void)layoutAnimatedLayer {
    CALayer *layer = self.animatedLayer;
    [self.layer addSublayer:layer];

    CGFloat viewW   = CGRectGetWidth(self.bounds);
    CGFloat viewH   = CGRectGetHeight(self.bounds);
    CGFloat layerW  = CGRectGetWidth(layer.bounds);
    CGFloat layerH  = CGRectGetHeight(layer.bounds);

    CGFloat widthDiff  = viewW - layerW;
    CGFloat heightDiff = viewH - layerH;

    CGFloat positionX  = viewW - layerW * 0.5 - widthDiff * 0.5;
    CGFloat positionY  = viewH - layerH * 0.5 - heightDiff * 0.5;

    layer.position = CGPointMake(positionX, positionY);

    self.backgroundLayer.position = layer.position;
}

#pragma mark - 懒加载
- (CAShapeLayer *)backgroundLayer {
    if (!_backgroundLayer) {
        CGPoint arcCenter = [self layerCenter];

        UIBezierPath *smoothedPath = [UIBezierPath bezierPathWithArcCenter:arcCenter
                                                                    radius:self.radius
                                                                startAngle:-M_PI_2
                                                                  endAngle:M_PI + M_PI_2
                                                                 clockwise:YES];

        _backgroundLayer               = [CAShapeLayer layer];
        _backgroundLayer.contentsScale = [UIScreen mainScreen].scale;
        _backgroundLayer.frame         = CGRectMake(0.f, 0.f, arcCenter.x * 2, arcCenter.y * 2);
        _backgroundLayer.fillColor     = [UIColor clearColor].CGColor;
        _backgroundLayer.strokeColor   = self.bgColor.CGColor;
        _backgroundLayer.lineWidth     = self.lineWidth;
        _backgroundLayer.lineCap       = kCALineCapRound;
        _backgroundLayer.lineJoin      = kCALineJoinBevel;
        _backgroundLayer.path          = smoothedPath.CGPath;
        _backgroundLayer.strokeEnd     = 1.0f;
    }
    return _backgroundLayer;
}

- (CAShapeLayer *)animatedLayer {
    if (!_animatedLayer) {
        [self.layer addSublayer:self.backgroundLayer];

        CGPoint arcCenter = [self layerCenter];
        _animatedLayer               = [CAShapeLayer layer];
        _animatedLayer.contentsScale = [UIScreen mainScreen].scale;
        _animatedLayer.frame         = CGRectMake(0, 0, arcCenter.x * 2, arcCenter.y * 2);
        _animatedLayer.fillColor     = [UIColor clearColor].CGColor;
        _animatedLayer.strokeColor   = self.strokeColor.CGColor;
        _animatedLayer.lineWidth     = self.lineWidth;
        _animatedLayer.lineCap       = kCALineCapRound;
        _animatedLayer.lineJoin      = kCALineJoinBevel;

        switch (self.loadingStyle) {
            case YSLoadingStyleCircle:
                [self setupCircleAnim:_animatedLayer];
                break;
            case YSLoadingStyleCircleMask:
                [self setupCircleMaskAnim:_animatedLayer];
                break;

            default:
                break;
        }
    }
    return _animatedLayer;
}

- (UILabel *)failureLabel {
    if (!_failureLabel) {
        _failureLabel           = [UILabel new];
        _failureLabel.font      = [UIFont systemFontOfSize:16.0f];
        _failureLabel.textColor = [UIColor whiteColor];
        _failureLabel.text      = @"图片加载失败，请检查网络后重试";
        _failureLabel.textAlignment = NSTextAlignmentCenter;
        [_failureLabel sizeToFit];

        _failureLabel.center = CGPointMake(self.bounds.size.width * 0.5, self.bounds.size.height * 0.5);
    }
    return _failureLabel;
}

- (void)setupCircleAnim:(CAShapeLayer *)layer {
    CGPoint arcCenter = [self layerCenter];

    UIBezierPath *smoothedPath = [UIBezierPath bezierPathWithArcCenter:arcCenter
                                                                radius:self.radius
                                                            startAngle:-M_PI_2
                                                              endAngle:M_PI_2 - M_PI_4
                                                             clockwise:YES];
    layer.path = smoothedPath.CGPath;
}

- (void)setupCircleMaskAnim:(CAShapeLayer *)layer {
    CGPoint arcCenter = [self layerCenter];

    UIBezierPath *smoothedPath = [UIBezierPath bezierPathWithArcCenter:arcCenter
                                                                radius:self.radius
                                                            startAngle:(M_PI_2 * 3)
                                                              endAngle:(M_PI_2 * 11)
                                                             clockwise:YES];

    layer.path = smoothedPath.CGPath;

    CALayer *maskLayer = [CALayer layer];
    maskLayer.contents  = (__bridge id)[YSLoadingImage(@"angle-mask") CGImage];
    maskLayer.frame     = layer.bounds;
    layer.mask          = maskLayer;
}

#pragma mark - setter
- (void)setFrame:(CGRect)frame {
    if (!CGRectEqualToRect(frame, super.frame)) {
        [super setFrame:frame];

        if (self.superview) {
            [self layoutAnimatedLayer];
        }
    }
}

- (void)setLineWidth:(CGFloat)lineWidth {
    _lineWidth = lineWidth;

    self.animatedLayer.lineWidth   = lineWidth;
    self.backgroundLayer.lineWidth = lineWidth;

    [self layoutIfNeeded];
}

- (void)setRadius:(CGFloat)radius {
    if (radius != _radius) {
        _radius = radius;

        [self.animatedLayer removeFromSuperlayer];
        self.animatedLayer = nil;

        [self.backgroundLayer removeFromSuperlayer];
        self.backgroundLayer = nil;

        if (self.superview) {
            [self layoutAnimatedLayer];
        }
    }

    [self layoutIfNeeded];
}

- (void)setBgColor:(UIColor *)bgColor {
    _bgColor = bgColor;

    self.backgroundLayer.strokeColor = bgColor.CGColor;
}

- (void)setStrokeColor:(UIColor *)strokeColor {
    _strokeColor = strokeColor;

    self.animatedLayer.strokeColor = strokeColor.CGColor;
}

- (CGSize)sizeThatFits:(CGSize)size {
    CGFloat wh = (self.radius + self.lineWidth * 0.5 + 5 ) * 2;
    return CGSizeMake(wh, wh);
}

- (CGPoint)layerCenter {
    CGFloat xy = self.radius + self.lineWidth * 0.5 + 5;
    return CGPointMake(xy, xy);
}

#pragma mark - public method
- (void)startLoading {
    [self.failureLabel removeFromSuperview];
    self.failureLabel = nil;

    if (self.loadingStyle == YSLoadingStyleCircle) {
        CABasicAnimation *rotateAnimation   = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
        rotateAnimation.timingFunction      = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
        rotateAnimation.fromValue           = @0;
        rotateAnimation.toValue             = @(M_PI * 2);
        rotateAnimation.duration            = 0.8;
        rotateAnimation.repeatCount         = HUGE;
        rotateAnimation.removedOnCompletion = NO;
        [self.animatedLayer addAnimation:rotateAnimation forKey:nil];

    } else if (self.loadingStyle == YSLoadingStyleCircleMask) {
        NSTimeInterval animationDuration   = 1;
        CAMediaTimingFunction *linearCurve = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];

        CABasicAnimation *animation   = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
        animation.fromValue           = @0;
        animation.toValue             = @(M_PI * 2);
        animation.duration            = animationDuration;
        animation.timingFunction      = linearCurve;
        animation.removedOnCompletion = NO;
        animation.repeatCount         = HUGE;
        animation.fillMode            = kCAFillModeForwards;
        animation.autoreverses        = NO;
        [self.animatedLayer.mask addAnimation:animation forKey:@"rotate"];

        CAAnimationGroup *animationGroup    = [CAAnimationGroup animation];
        animationGroup.duration             = animationDuration;
        animationGroup.repeatCount          = HUGE;
        animationGroup.removedOnCompletion  = NO;
        animationGroup.timingFunction       = linearCurve;

        CABasicAnimation *strokeStartAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
        strokeStartAnimation.fromValue = @0.015;
        strokeStartAnimation.toValue   = @0.515;

        CABasicAnimation *strokeEndAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
        strokeEndAnimation.fromValue = @0.485;
        strokeEndAnimation.toValue   = @0.985;

        animationGroup.animations = @[strokeStartAnimation, strokeEndAnimation];
        [self.animatedLayer addAnimation:animationGroup forKey:@"progress"];
    }
}

- (void)stopLoading {
    [self.layer removeAllAnimations];
    [self removeFromSuperview];
}

- (void)showFailure {
    [self.animatedLayer removeFromSuperlayer];
    self.animatedLayer = nil;

    [self.layer removeAllAnimations];

    [self addSubview:self.failureLabel];
}

- (void)dealloc {
    [self.layer removeAllAnimations];
    [self.animatedLayer removeFromSuperlayer];
    self.animatedLayer = nil;
    [self.backgroundLayer removeFromSuperlayer];
    self.backgroundLayer = nil;
}

@end
